#!/bin/bash

usage() {
echo "
Search Youtube.

Usage: youtube-search [OPTIONS] [\"SEARCH STRING\"]

Requires jshon and youtube-dl to be in PATH (or a youtube-dl compatible
executable, see -e option). Requires perl and HTML::Entities.

You can provide a search string in double quotes on the command line,
or enter it interactively.

It helps if xclip and/or tput are available, but the script works without those.

OPTIONS
    -l      List more detail for each result (slower, larger download).
    -f      Full width - don't cut long strings to terminal width.
    -m int  Maximum number of results shown Default: $max_results.
            We suspect that only the values 3 or 10 should be used.
    -t int  Timeout for URL retrieval. Default: $timeout.
    -e str  Use this executable instead of youtbe-dl.
    -M str  Use this application to open the selected Youtube URL.
            Tested with youtube-dl and also mpv.
    -D      Debug: dump complete json result and more.
    -h      This help.
"
exit 1
}

base_url='https://m.youtube.com'
minlen=3 # minimum length for search term

# character for separator line
sepchar="-"

# Colors
RED='\033[31m'
BLUE='\033[34m'
CYAN='\033[36m'
GREEN='\033[32m'
YELLOW='\033[33m'
END='\033[0;0m'
BOLD='\033[1m'

#Set number of video results here.
max_results=3
timeout=10
fullwidth=False
debug=0
uts=''
mpv=()
YTDL="${YTDL:-youtube-dl}"
ytdlopts=( --flat-playlist --sub-lang en )
options=( title description duration view_count id )

# Parsing the command line
while getopts "lfm:t:e:M:Dh" opt; do
    case $opt in
        l)
            options=( "${options[@]}" uploader_id like_count dislike_count thumbnail )
            ytdlopts=( --sub-lang en )
            ;;
        f)
            fullwidth=True
            ;;
        m)
            max_results="$OPTARG"
            ;;
        t)
            timeout="$OPTARG"
            ;;
        e)
            which "$OPTARG" >/dev/null && YTDL="$OPTARG" || exit 1
            ;;
        M)
            mpv=( $OPTARG )
            which "${mpv[0]}" >/dev/null || exit 1
            ;;
        D)
            debug=1
            ;;
        h|*)
            usage
            ;;
    esac
done
shift $((OPTIND-1))

# quick dependency check
for dep in "$YTDL" jshon; do
    type "$dep" >/dev/null || exit 1
done
perl -MHTML::Entities -e 1 || exit 1

sep=''
columns="$(tput cols)"
[ -z "$columns" ] && columns=80
# adjust separator width to terminal width
for ((i=0;i<columns;i++)); do sep="$sep$sepchar"; done
unset sepchar

# Interactively obtain search term
uts="${1%%$'\n'*}" # cut before first newline
read -r -e -i "$uts" -p "Enter search term: " uts
xclip -selection clipboard <<<"$uts";xclip -selection primary <<<"$uts"
uts="$(perl -CS -MHTML::Entities -pe 'encode_entities($_);' <<<"$uts")"
[ -z "$uts" ] && exit 1
[[ "$debug" == 1 ]] && { echo "$sep"; echo "Encoded search term: $uts"; echo "Manual search: https://www.youtube.com/results?search_query=$uts"; echo "$sep"; }

# adjust tabstops to longest key, cut strings to terminal width - tabstop
longest=0
for i in "${options[@]}"; do ((${#i} > longest)) && longest=${#i}; done
longest=$((longest+3)); tabs $longest

#### AND ACTION! ####
mapfile -n "$max_results" -t results <<<"$("$YTDL" "${ytdlopts[@]}" --socket-timeout "$timeout" --dump-json "ytsearch$max_results:$uts")"
#### AND ACTION! ####

i=0
url=()
for line in "${results[@]}"; do
    echo -e "$YELLOW$i ${sep::-$(( ${#i} + 1 ))}$END"
    [ -z "$line" ] && echo "Empty line" && continue
    [[ "$debug" == 1 ]] && jshon <<<"$line" && echo -e "$YELLOW$sep$END"
    for o in "${options[@]}"; do
        res="$(jshon -e $o -u <<<"$line")"
        reswidth="$((columns-longest))"
        [[ "$fullwidth" == False ]] && (( reswidth > 15 )) && res="${res:0:$reswidth}"
        case "$o" in
        id) res="$base_url/watch?v=$res"
            url[$i]="$res"
            o="URL"
            ;;
        duration)
            res="${res%%.*}"
             ((h=${res}/3600))
             ((m=(${res}%3600)/60))
             ((s=${res}%60))
            res="$(printf "%02d:%02d:%02d\n" $h $m $s)"
            ;;
        esac
    echo -e "$GREEN$o:$END\t$res"
    done
    ((i++))
done
echo
while :; do
    answer="-1"
    until [[ "$answer" =~ ^[0-9]+$ ]] && (( answer >= 0 )) && (( answer < i )); do
        read -p "Select URL no. (q to quit): " answer
        [[ "$answer" == q ]] && exit
    done
    url="${url[answer]}"
    if which xclip >/dev/null 2>&1; then
        xclip -selection clipboard <<<"$url"
        xclip -selection primary <<<"$url"
        echo "Copied $url to clipboard and primary."
    else
        echo "$url"
    fi
    [[ "${mpv[0]}" != '' ]] && echo "Launching ${mpv[@]} $url" && "${mpv[@]}" "$url"
done
